package apidoc

import (
	"autoTestNew/pkg/commonType"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/parnurzeal/gorequest"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"io/ioutil"
	"net/http"
	"sort"
	"sync"
	"time"
)

var mutex sync.Mutex

// 创建测试任务
func (s *Service) createTestTask(c *gin.Context) {
	var task commonType.Task
	err := c.BindJSON(&task)
	if err != nil {
		// 创建结构化的错误响应
		errorResponse := commonType.ErrorResponse{
			Error:   "BadRequest",
			Message: "Failed to bind JSON: " + err.Error(),
		}
		c.JSON(http.StatusBadRequest, errorResponse)
		return
	}

	task, err = s.taskStore.Create(c.Request.Context(), task)
	if err != nil {
		// 创建结构化的错误响应
		errorResponse := commonType.ErrorResponse{
			Error:   "InternalServerError",
			Message: "Failed to create task: " + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, errorResponse)
		return
	}
	successResponse := commonType.SuccessResponse{
		Status:  20000,
		Message: "Task created successfully",
		Data:    task,
	}
	c.JSON(http.StatusOK, successResponse)
}

// 测试请求 http://localhost:8001/api/notification/toNotify
func (s *Service) testRequest(c *gin.Context) {
	// 创建Gorequest的HTTP客户端
	gorequestClient := gorequest.New()

	// 设置请求头和请求方法
	resp, body, errs := gorequestClient.Get("http://127.0.0.1:8001/api/notification/toNotify").
		End()

	// 检查请求是否有错误发生
	if errs != nil {
		fmt.Println("Error sending request:", errs)
		return
	}

	// 确保响应体关闭
	defer resp.Body.Close()

	// 打印响应体
	fmt.Println("Response received:", body)
}

// 执行测试任务
func (s *Service) executeTestTask(c *gin.Context) {
	// 获取task_id
	taskID := c.Query("task_id")
	// 从数据库中查询task
	taskObjectID, err := primitive.ObjectIDFromHex(taskID)
	if err != nil {
		errorResponse := commonType.ErrorResponse{
			Error:   "BadRequest",
			Message: "Invalid task id: " + taskID,
		}
		c.JSON(http.StatusBadRequest, errorResponse)
		return
	}
	task, err := s.taskStore.Get(c.Request.Context(), taskObjectID)
	if err != nil {
		errorResponse := commonType.ErrorResponse{
			Error:   "InternalServerError",
			Message: "Failed to find task from MongoDB by id: " + taskID,
		}
		c.JSON(http.StatusInternalServerError, errorResponse)
		return
	}

	// 生成测试记录 新增record
	record := commonType.Record{
		TaskID:    &taskObjectID,
		Executor:  "周格林",
		StartTime: time.Now().Format("2006-01-02 15:04:05"),
		EndTime:   "",
		Status:    1,
	}
	// 插入record数据库
	record, err = s.recordStore.Create(c.Request.Context(), record)
	if err != nil {
		errorResponse := commonType.ErrorResponse{
			Error:   "InternalServerError",
			Message: "Failed to create record",
		}
		c.JSON(http.StatusInternalServerError, errorResponse)
		return
	}

	// 生成测试微服务
	traceTree := task.TraceTree
	for _, node := range traceTree.Nodes {
		testMicroservice := commonType.TestMicroservice{
			RecordID:   record.ID,
			Name:       node.Name,
			TestStatus: 0,
			FaultList:  nil,
			Request:    node.TraceRequest,
		}
		for _, faultConfig := range task.FaultConfig {
			if faultConfig.ServiceName == node.Name {
				testMicroservice.FaultList = faultConfig.FaultList
				break
			}
		}
		// 插入testMicroservice数据库
		mutex.Lock() // 锁定
		testMicroservice, err = s.testMicroserviceStore.Create(c.Request.Context(), testMicroservice)
		mutex.Unlock() // 确保函数结束时解锁
		if err != nil {
			errorResponse := commonType.ErrorResponse{
				Error:   "InternalServerError",
				Message: "Failed to create testMicroservice",
			}
			c.JSON(http.StatusInternalServerError, errorResponse)
			return
		}
		// 创建协程
		go s.handleTestMicroservices(c, testMicroservice)
	}
}

// 处理testMicroservices
func (s *Service) handleTestMicroservices(c *gin.Context, testMicroservices commonType.TestMicroservice) {
	ctx := context.Background() // 创建独立的 context
	testMicroserviceDone := make(chan bool)
	for {
		// 判断是否具有下游服务
		if s.canExecute(c, testMicroservices) {
			// 执行测试
			// 1. 更新testMicroservices的状态为执行中
			testMicroservices.TestStatus = 1
			err := s.testMicroserviceStore.Update(ctx, *testMicroservices.ID, testMicroservices)
			if err != nil {
				return
			}
			// 2. 执行测试
			s.executeTest(c, testMicroservices, testMicroserviceDone)
			// 3. 更新testMicroservices的状态为执行完成
			testMicroservices.TestStatus = 2
			err = s.testMicroserviceStore.Update(ctx, *testMicroservices.ID, testMicroservices)
			if err != nil {
				return
			}
			break
		}
	}

}

/*
当前测试微服务是否可以执行
可以执行返回true 无下游微服务或者下游微服务执行完成
不可以执行返回false
*/
func (s *Service) canExecute(c *gin.Context, testMicroservice commonType.TestMicroservice) bool {
	ctx := context.Background() // 创建独立的 context
	// 1. 根据recordId查询对应的taskId 然后根据taskId查询task 最后根据task查询traceTree
	traceTree := s.getTraceTree(testMicroservice)
	// 2. 根据testMicroservice.name查询下游微服务
	downstreamServices := s.getDownstreamMicroservices(testMicroservice, traceTree)
	if len(downstreamServices) > 0 {
		// 2.1 如果有下游微服务则挨个判断每个下游微服务的测试状态
		for _, testMicroserviceName := range downstreamServices {
			tm, _ := s.testMicroserviceStore.GetByNameAndRecordId(ctx, testMicroserviceName, *testMicroservice.RecordID)
			if tm.TestStatus != 2 {
				return false
			}
		}
	}
	return true
}

// 根据testMicroservice查询当前traceTree
func (s *Service) getTraceTree(testMicroservice commonType.TestMicroservice) commonType.TraceTree {
	ctx := context.Background() // 创建独立的 context
	// 1. 根据recordId查询对应的taskId 然后根据taskId查询task 最后根据task查询traceTree
	record, err := s.recordStore.Get(ctx, *testMicroservice.RecordID)
	if err != nil {
		return commonType.TraceTree{}
	}
	task, err := s.taskStore.Get(ctx, *record.TaskID)
	if err != nil {
		return commonType.TraceTree{}
	}
	return task.TraceTree
}

/*
获取所有下游微服务
*/
func (s *Service) getDownstreamMicroservices(testMicroservice commonType.TestMicroservice, tree commonType.TraceTree) []string {
	// 获取当前微服务的名称
	name := testMicroservice.Name
	targetNodeId := -1

	// 从树中找到当前微服务节点的ID
	for _, node := range tree.Nodes {
		if node.Name == name {
			targetNodeId = node.ID
			break // 找到后退出循环
		}
	}

	if targetNodeId == -1 {
		return nil // 如果没有找到节点，返回空切片
	}

	// 创建一个空切片存储下游微服务的名称
	downstreamServices := []string{}

	// 遍历所有的边，找到源是当前节点的所有边
	for _, edge := range tree.Edges {
		if edge.Source == targetNodeId {
			// 找到目标节点ID对应的名称，并添加到结果切片中
			for _, node := range tree.Nodes {
				if node.ID == edge.Target {
					downstreamServices = append(downstreamServices, node.Name)
				}
			}
		}
	}

	return downstreamServices
}

/*
执行测试
*/
func (s *Service) executeTest(c *gin.Context, testMicroservice commonType.TestMicroservice, testMicroserviceDone chan bool) {
	ctx := context.Background() // 创建独立的 context
	testcaseDone := make(chan bool)
	// 1. 生成测试用例
	s.generateTestCase(c, testMicroservice)
	testCaseList, _ := s.testCaseStore.GetListByTestMicroserviceId(ctx, *testMicroservice.ID)
	// 2. 执行测试用例
	for _, testCase := range testCaseList {
		go s.executeTestCase(c, testCase, testMicroservice.Request, testcaseDone)
	}
	// 3. 等待所有测试用例执行完成
	for i := 0; i < len(testCaseList); i++ {
		<-testcaseDone
	}
	// 更新testMicroservice的状态为执行完成
	testMicroservice.TestStatus = 2
	err := s.testMicroserviceStore.Update(ctx, *testMicroservice.ID, testMicroservice)
	if err != nil {
		return
	}
	// 4. 通知测试微服务执行完成
	testMicroserviceDone <- true
}

// 生成测试用例
func (s *Service) generateTestCase(c *gin.Context, testMicroservice commonType.TestMicroservice) {
	ctx := context.Background() // 创建独立的 context
	traceTree := s.getTraceTree(testMicroservice)
	// 获取当前微服务故障候选列表
	faultList := testMicroservice.FaultList
	faultListLen := len(faultList)
	// 定义一个map，用于存储每个服务名称及其对应的测试用例ID数组
	testCasesByService := make(map[string][]string)

	// 获取下游微服务
	downstreamServices := s.getDownstreamMicroservices(testMicroservice, traceTree)
	if len(downstreamServices) > 0 {
		// 遍历所有下游微服务，获取各个下游微服务的测试用例
		for _, testMicroserviceName := range downstreamServices {
			// 获取下游测试微服务
			tm, err := s.testMicroserviceStore.GetByNameAndRecordId(ctx, testMicroserviceName, *testMicroservice.RecordID)
			if err != nil {
				// 处理错误，比如日志记录
				continue // 如果出错，则跳过当前迭代
			}

			// 根据测试微服务id获取所有测试用例
			downstreamTestCases, err := s.testCaseStore.GetListByTestMicroserviceId(ctx, *tm.ID)
			if err != nil {
				// 处理错误，比如日志记录
				continue // 如果出错，则跳过当前迭代
			}
			// 准备存储当前服务的测试用例ID列表
			var testCaseIDs []string
			for _, testCase := range downstreamTestCases {
				if testCase.ID != nil {
					testCaseIDs = append(testCaseIDs, testCase.ID.Hex()) // 将ObjectID转换为字符串
				}
			}
			// 将测试用例ID列表存储到map中，使用服务名称作为键
			testCasesByService[testMicroserviceName] = testCaseIDs
		}
	}
	// 生成测试用例
	for i := -1; i < faultListLen; i++ {
		if len(testCasesByService) > 0 {
			// 生成依赖组合
			combinations := generateTestCaseCombinations(testCasesByService)

			fmt.Println("combinations: ", combinations)
			for _, combination := range combinations {
				// 初始化一个用于存储转换后的 ObjectID 切片
				var dependencyObjectIDs []*primitive.ObjectID

				// 遍历每个测试用例ID的字符串形式
				for _, idStr := range combination {
					objID, err := primitive.ObjectIDFromHex(idStr)
					if err != nil {
						// 处理错误，例如：无效的十六进制字符串
						fmt.Println("Error converting hex to ObjectID:", err)
						continue // 如果出错，则跳过当前ID
					}
					dependencyObjectIDs = append(dependencyObjectIDs, &objID)
				}
				// 生成测试用例
				testCase := commonType.TestCase{
					TestMicroserviceID: testMicroservice.ID,
					SelectedFaultID:    i,
					Dependency:         dependencyObjectIDs,
					Status:             0,
					Response:           commonType.StoredResponse{},
				}
				// 插入testCase数据库
				testCase, err := s.testCaseStore.Create(ctx, testCase)
				if err != nil {
					// 处理错误，比如日志记录
					continue // 如果出错，则跳过当前迭代
				}
			}
		} else {
			// 生成测试用例
			testCase := commonType.TestCase{
				TestMicroserviceID: testMicroservice.ID,
				SelectedFaultID:    i,
				Dependency:         nil,
				Status:             0,
				Response:           commonType.StoredResponse{},
			}
			// 插入testCase数据库
			testCase, err := s.testCaseStore.Create(ctx, testCase)
			if err != nil {
				// 处理错误，比如日志记录
				continue // 如果出错，则跳过当前迭代
			}
		}
	}

}

// 生成依赖组合
func generateTestCaseCombinations(testCasesByService map[string][]string) [][]string {
	var keys []string
	for key := range testCasesByService {
		keys = append(keys, key)
	}
	sort.Strings(keys) // 确保顺序，以便结果是一致的

	var result [][]string
	if len(keys) == 0 {
		return result
	}

	// 初始化累积器
	firstKey := keys[0]
	for _, id := range testCasesByService[firstKey] {
		result = append(result, []string{id})
	}

	// 计算笛卡尔积
	for _, key := range keys[1:] {
		result = cartesianProduct(result, testCasesByService[key])
	}

	return result
}
func cartesianProduct(acc [][]string, next []string) [][]string {
	var result [][]string
	for _, existing := range acc { // 对于已经累积的每一组组合
		for _, add := range next { // 对于新列表中的每个元素
			newCombo := append([]string(nil), existing...) // 复制现有组合
			newCombo = append(newCombo, add)               // 添加新元素
			result = append(result, newCombo)              // 将新组合加入结果集
		}
	}
	return result
}

// 执行测试用例
func (s *Service) executeTestCase(c *gin.Context, testCase commonType.TestCase, request commonType.Request, testcaseDone chan bool) {
	ctx := context.Background() // 创建独立的 context
	// 1. 更新测试用例状态为执行中
	testCase.Status = 1
	err := s.testCaseStore.Update(ctx, *testCase.ID, testCase)
	if err != nil {
		return
	}
	// 2. 发起请求
	s.sendRequest(c, testCase, request)
	// 3. 更新测试用例状态为执行完成
	testCase.Status = 2
	err = s.testCaseStore.Update(ctx, *testCase.ID, testCase)
	if err != nil {
		return
	}
	// 4. 通知测试用例执行完成
	testcaseDone <- true
}

func (s *Service) sendRequest(c *gin.Context, testCase commonType.TestCase, request commonType.Request) {
	ctx := context.Background() // 创建独立的 context

	// 1. 构造请求
	// 将请求数据转为JSON
	jsonData, err := json.Marshal(request.Data)
	if err != nil {
		fmt.Println("Error marshaling data:", err)
		return
	}

	// 创建Gorequest的HTTP客户端
	gorequestClient := gorequest.New()

	// 设置请求头和请求方法
	resp, body, errs := gorequestClient.CustomMethod(request.Method, request.URL).
		Set("Content-Type", "application/json").
		Send(string(jsonData)).
		End()

	// 检查请求是否有错误发生
	if errs != nil {
		fmt.Println("Error sending request:", errs)
		return
	}

	// 确保响应体关闭
	defer resp.Body.Close()

	// 2. 更新测试用例的响应信息
	// 注意：Gorequest已经帮你读取了响应体，存储在body变量中
	rsp := http.Response{
		StatusCode: resp.StatusCode,
		Body:       ioutil.NopCloser(bytes.NewBufferString(body)),
		Header:     resp.Header,
	}

	testCase.Response, _ = convertResponse(&rsp)

	// 3. 更新测试用例
	errUpdate := s.testCaseStore.Update(ctx, *testCase.ID, testCase)
	if errUpdate != nil {
		fmt.Println("Error updating testCase:", errUpdate)
		return
	}

	fmt.Println("Response received:", body)
}

type Task struct {
	ID          *primitive.ObjectID  `bson:"_id,omitempty" json:"_id"`
	Name        string               `bson:"name" json:"name"`
	ApiDoc      *primitive.ObjectID  `bson:"api_doc,omitempty" json:"api_doc"`
	TraceTree   commonType.TraceTree `bson:"trace_tree" json:"trace_tree"`
	FaultConfig []commonType.Fault   `bson:"fault_config" json:"fault_config"`
}

func convertResponse(r *http.Response) (commonType.StoredResponse, error) {
	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return commonType.StoredResponse{}, err
	}
	// 确保关闭原始响应体
	r.Body.Close()

	return commonType.StoredResponse{
		StatusCode: r.StatusCode,
		Headers:    r.Header,
		Body:       string(bodyBytes),
	}, nil
}
